package edu.iu.criminfo.voronoi.kmeans;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import edu.iu.criminfo.voronoi.cases.Case;

public class KMeans {
	private List<Cluster> clusterList;
	private List<Case> caseList;
	private String clusteringAlgorithm;
	public final double TOLERANCE = 5;

	private double convergeThreshold = 0;

	public KMeans(List<Cluster> clusterList, List<Case> caseList, String clusteringAlgorithm) {
		this.clusterList = clusterList;
		this.caseList = caseList;
		this.clusteringAlgorithm = clusteringAlgorithm;
	}

	public void updateClusters() {
		/* Please make sure every case has been inserted */
		for (Cluster cluster : clusterList) {
			cluster.updateCenter();
		}
	}

	public void insertCasesToClusters() {
		/* please make sure caseList in every cluster is empty */
		int index = 0;

		for (Case aCase : caseList) {
			index = aCase.inWhichCluster(clusterList);
			clusterList.get(index).addCase(aCase);
		}
	}

	public void insertCaseToCluseters(double alpha, double capacity) {
		/* please make sure caseList in every cluster is empty */
		int index = 0;

		for (Case aCase : caseList) {
			index = aCase.inWitchCluster(clusterList, alpha, capacity);
			clusterList.get(index).addCase(aCase);
		}
	}

	public void startClustering() {
		int counter = 0;
		/* make sure every cluster is empty */
		for (Cluster cluster : clusterList) {
			cluster.clearAllCases();
		}

		do {// Change to Do while loop
			insertCasesToClusters();
			/* Every case has been inserted */
			updateClusters();
			System.out.println(++counter + " times update");
		} while (!isConverged());

		if (clusteringAlgorithm.equalsIgnoreCase("K-means")) {
			insertCasesToClusters();
		} else if (clusteringAlgorithm.equalsIgnoreCase("Modified_K-means")){
			insertCaseToCluseters(0.75, ((double) caseList.size() / clusterList
			.size())
			+ TOLERANCE);
		}



		System.out.println("converged");
	}

	public boolean isConverged() {
		for (Cluster cluster : clusterList) {
			if (!cluster.isConverged(convergeThreshold)) {
				return false;
			}
		}
		return true;
	}

	public void setConvergeThreshold(double convergeThreshold) {
		this.convergeThreshold = convergeThreshold;
	}

	public void writeResultToFile(String filePath) {
		try {
			File file = new File(filePath);
			BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
					file));
			int i = 0;
			for (Cluster cluster : clusterList) {
				bufferedWriter.write(i + " th cluster:");
				bufferedWriter.newLine();
				
				cluster.writeToWriter(bufferedWriter);
				i++;
			}
			bufferedWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
